/**


 */
package org.mybatis.generator.codegen.mybatis3.model;

import org.mybatis.generator.api.dom.OutputUtilities;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.codegen.AbstractJavaGenerator;

import java.util.ArrayList;
import java.util.List;


public class ServiceImpGenerator extends AbstractJavaGenerator {

    public ServiceImpGenerator() {
        super();
    }

    private Field getServiceImpBaseFile() {

        Field field = new Field(
                introspectedTable.getDomainFirstNameLowerCase() + "Mapper",
                new FullyQualifiedJavaType(introspectedTable.
                        getDomianName() + "Mapper")
        );

        field.setVisibility(JavaVisibility.PRIVATE);
        field.addAnnotation("@Autowired");

        return field;
    }

    public List<Method> getServiceImpMethod(String mapperName) {

        List<Method> list = new ArrayList<Method>();

        list.add(getDeleteMethod(mapperName));
        list.add(getInsertMethod(mapperName));
        list.add(getSelectMethod(mapperName));
        list.add(getUpdateMethod(mapperName));

        return list;
    }

    private Method getSelectMethod(String mapperName) {

        StringBuilder sb = new StringBuilder();
        Method method = new Method(sb.toString());
        sb.append("@Override");
        method.addAnnotation(sb.toString());
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName(introspectedTable.getSelectByPrimaryKeyStatementId());

        sb.setLength(0);
        sb.insert(0, "List<").append(introspectedTable.getDomianName()).append(">");
        method.setReturnType(new FullyQualifiedJavaType(sb.toString()));

        method.addParameter(new Parameter(
                new FullyQualifiedJavaType(introspectedTable.
                        getDomianName()),
                introspectedTable.getDomainFirstNameLowerCase()
        ));


        sb.setLength(0);
        sb.append("try {");
        OutputUtilities.newLine(sb);
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append("return ");
        sb.append(mapperName);
        sb.append(".");
        sb.append(introspectedTable.getSelectByPrimaryKeyStatementId());
        sb.append("(");
        sb.append(introspectedTable.getDomainFirstNameLowerCase());
        sb.append(");");
        OutputUtilities.newLine(sb);
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 2);
        sb.append("} catch (Exception e) {");
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append("e.printStackTrace();");
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append("return null;");
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 2);
        sb.append("}");
        method.addBodyLine(sb.toString());

        return method;
    }

    private Method getInsertMethod(String mapperName) {
        StringBuilder sb = new StringBuilder();
        sb.append(introspectedTable.getInsertSelectiveStatementId());
        Method method = new Method(sb.toString());
        sb.setLength(0);
        sb.append("@Override");
        method.addAnnotation(sb.toString());

        method.setVisibility(JavaVisibility.PUBLIC);

        sb.setLength(0);
        method.setReturnType(FullyQualifiedJavaType.getStringInstance());
        method.addParameter(new Parameter(
                new FullyQualifiedJavaType(introspectedTable.
                        getDomianName()),
                introspectedTable.getDomainFirstNameLowerCase()
        ));


        sb.setLength(0);
        sb.append("try {");
        OutputUtilities.newLine(sb);
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append(NOTE_IDGENERATE);
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append(introspectedTable.getDomainFirstNameLowerCase());
        sb.append(".");
        sb.append("setId");
        sb.append("(");
        sb.append("IdGenerate.getId()");
        sb.append(");");
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append(mapperName);
        sb.append(".");
        sb.append(introspectedTable.getInsertSelectiveStatementId());
        sb.append("(");
        sb.append(introspectedTable.getDomainFirstNameLowerCase());
        sb.append(");");
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append(NOTE_CONSTANTS);
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append("return ");
        sb.append("Constants.SUCCESS;");
        OutputUtilities.newLine(sb);
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 2);
        sb.append("} catch (Exception e) {");
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append("e.printStackTrace();");
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append("return ");
        sb.append("Constants.FAIL;");
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 2);
        sb.append("}");
        method.addBodyLine(sb.toString());

        return method;
    }

    private Method getUpdateMethod(String serviceName) {

        return getBaseMethod(
                serviceName,
                introspectedTable.getUpdateByPrimaryKeySelectiveStatementId(),
                FullyQualifiedJavaType.getStringInstance()
        );
    }


    private Method getDeleteMethod(String serviceName) {

        return getBaseMethod(
                serviceName,
                introspectedTable.getDeleteByPrimaryKeyStatementId(),
                FullyQualifiedJavaType.getStringInstance()
        );
    }

    private Method getBaseMethod(
            String mapperName,
            String typeName,
            FullyQualifiedJavaType returnTypeName
    ) {

        StringBuilder sb = new StringBuilder();
        Method method = new Method(sb.toString());
        sb.append("@Override");
        method.addAnnotation(sb.toString());
        method.setVisibility(JavaVisibility.PUBLIC);


        sb.setLength(0);
        method.setName(typeName);
        method.setReturnType(returnTypeName);
        method.addParameter(new Parameter(
                new FullyQualifiedJavaType(introspectedTable.
                        getDomianName()),
                introspectedTable.getDomainFirstNameLowerCase()
        ));


        sb.setLength(0);
        sb.append("try {");
        OutputUtilities.newLine(sb);
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append(mapperName);
        sb.append(".");
        sb.append(typeName);
        sb.append("(");
        sb.append(introspectedTable.getDomainFirstNameLowerCase());
        sb.append(");");
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append(NOTE_CONSTANTS);
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append("return ");
        sb.append("Constants.SUCCESS;");
        OutputUtilities.newLine(sb);
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 2);
        sb.append("} catch (Exception e) {");
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append("e.printStackTrace();");
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 3);
        sb.append("return ");
        sb.append("Constants.FAIL;");
        OutputUtilities.newLine(sb);
        OutputUtilities.javaIndent(sb, 2);
        sb.append("}");
        method.addBodyLine(sb.toString());

        return method;


    }


    @Override
    public List<CompilationUnit> getCompilationUnits() {

        TopLevelClass topLevelClass = createTopLevelClass();
        topLevelClassInitClass(topLevelClass);
        topLevelClassInitType(topLevelClass);
        Field f = getServiceImpBaseFile();
        topLevelClass.addField(f);
        List<Method> list = topLevelClass.getMethods();
        list.addAll(getServiceImpMethod(f.getName()));


        List<CompilationUnit> answer = new ArrayList<CompilationUnit>();
        answer.add(topLevelClass);
        return answer;
    }


    private TopLevelClass createTopLevelClass() {

        FullyQualifiedJavaType type = new FullyQualifiedJavaType(
                introspectedTable.getServiceImpType());

        return new TopLevelClass(type);
    }

    /**
     * 初始化TopLevelClass的Class
     *
     * @param topLevelClass
     */
    private void topLevelClassInitClass(TopLevelClass topLevelClass) {
        StringBuilder sb = new StringBuilder();
        sb.append("@Service");
        topLevelClass.setVisibility(JavaVisibility.PUBLIC);
        topLevelClass.addAnnotation(sb.toString());

        sb.setLength(0);
        sb.append("@Transactional");
        topLevelClass.addAnnotation(sb.toString());

        topLevelClass.addSuperInterface(
                new FullyQualifiedJavaType(introspectedTable.getDomianName() + "Service"));

    }

    /**
     * 初始化TopLevelClass的Type
     *
     * @param topLevelClass
     */
    private void topLevelClassInitType(TopLevelClass topLevelClass) {

        topLevelClass.addImportedType(introspectedTable.getBaseRecordType());
        topLevelClass.addImportedType(introspectedTable.getServiceType());
        topLevelClass.addImportedType(introspectedTable.getMyBatis3JavaMapperType());
        topLevelClass.addImportedType(getConstantsPackage());
        topLevelClass.addImportedType(getIdGeneratePackage());

        topLevelClass.addImportedType("java.util.List");
        topLevelClass.addImportedType("org.springframework.beans.factory.annotation.Autowired");
        topLevelClass.addImportedType("org.springframework.stereotype.Service");
        topLevelClass.addImportedType("org.springframework.transaction.annotation.Transactional");
    }


    private String getConstantsPackage() {
        StringBuilder sb = new StringBuilder();
        sb.append(getBasePackage());
        sb.append(".");
        sb.append("common");
        sb.append(".");
        sb.append("Constants");
        return sb.toString();
    }

    private String getIdGeneratePackage() {
        StringBuilder sb = new StringBuilder();
        sb.append(getBasePackage());
        sb.append(".");
        sb.append("common");
        sb.append(".");
        sb.append("IdGenerate");
        return sb.toString();
    }


    private String getBasePackage() {
        StringBuilder sb = new StringBuilder();
        sb.append(introspectedTable.getMyBatis3XmlMapperPackage());
        int index = sb.indexOf(".");
        index = sb.indexOf(".", index + 1);
        if (index == -1) {
            return "com";
        }
        return sb.substring(0,index);
    }
}
